﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Navigation;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Threading;
using Microsoft.Phone.Controls;
using DispatcherHelper = JustinAngel.Neurons.Framework.Helpers.DispatcherHelper;

namespace JustinAngel.Neurons.Framework.Navigation
{
    public class NavigationService : IAppService
    {
        [Dependency]
        public IMessenger Messenger { get; set; }

        public void StartService()
        {
            Messenger.Register<NavigateBackMessage>(this, OnNavigationBack);
            Messenger.Register<NavigateToMessage>(this, false, OnNavigateTo);
            Messenger.Register<DelayNavigateToMessage>(this, false, OnDelayNavigateTo);
        }

        private void OnDelayNavigateTo(DelayNavigateToMessage obj)
        {
            DispatcherTimerHelper.On(obj.Delay, () => OnNavigateTo(obj));
        }

        private List<Action> actionsToFireAfterNavigation = new List<Action>();
        private object _dataToSetAfterNavigation = null;
        private bool _registeredFailedNavigation = false;

        private void OnNavigateTo(NavigateToMessage obj)
        {
            if (obj.ActionToFireAfterNavigation != null)
            {
                InitializeNavigatedRegistration();
                actionsToFireAfterNavigation.Add(obj.ActionToFireAfterNavigation);
            }
            if (obj.Data != null)
            {
                InitializeNavigatedRegistration();
                _dataToSetAfterNavigation = obj.Data;
            }

            if (!_registeredFailedNavigation)
            {
                _registeredFailedNavigation = true;
                Frame.NavigationFailed += new NavigationFailedEventHandler(Frame_NavigationFailed);
            }
         
            DispatcherHelper.BeginInvokeOnUIThread(() => DoActualNavigation(obj));
        }


        private void DoActualNavigation(NavigateToMessage obj)
        {
            try
            {
                Frame.Navigate(new Uri(GetPageUriString(obj), UriKind.Relative));
            }
            catch (Exception ex)
            {
                FrameNavigationFailed(ex, GetPageUriString(obj));
            }
        }

        private string GetPageUriString(NavigateToMessage obj)
        {
            return string.Format("/Pages/{0}/{0}Page.xaml", obj.NavigationTarget.PageName);
        }


        private void FrameNavigationFailed(Exception ex, string Uri)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                System.Diagnostics.Debugger.Break();
            }
        }

        void Frame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            e.Handled = true;
            FrameNavigationFailed(e.Exception, e.Uri.OriginalString);
       
        }

        bool _initialized = false;
        private void InitializeNavigatedRegistration()
        {
            if (_initialized)
                return;
            _initialized = true;
            Frame.Navigated += new NavigatedEventHandler(Frame_Navigated);
        }

        void Frame_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            foreach (var messageBase in actionsToFireAfterNavigation)
            {
                messageBase.Invoke();
            }
            actionsToFireAfterNavigation.Clear();

            if (_dataToSetAfterNavigation != null)
            {
                PhoneApplicationPage page = Frame.Content as PhoneApplicationPage;
                if (page != null)
                {
                    VViewModelBase VM = page.DataContext as VViewModelBase;
                    if (VM != null)
                    {
                        VM.Data = _dataToSetAfterNavigation;
                    }
                    else
                    {
                        page.Tag = _dataToSetAfterNavigation;
                    }
                  
                }
                _dataToSetAfterNavigation = null;
            }
        }

        private void OnNavigationBack(NavigateBackMessage obj)
        {
            if (Frame.CanGoBack)
            {
                try
                {
                    Frame.GoBack();
                }
                catch (Exception ex)
                {
                    FrameNavigationFailed(ex, "Back");
                }
            }
        }

        public void StopService()
        {
            Frame.Navigated -= new NavigatedEventHandler(Frame_Navigated);
            Messenger.Unregister<NavigateBackMessage>(this, OnNavigationBack);
            Messenger.Unregister<NavigateToMessage>(this, OnNavigateTo);
        }

        private PhoneApplicationFrame _frame;
        public PhoneApplicationFrame Frame
        {
            get
            {
                if (_frame == null)
                {
                    _frame = (PhoneApplicationFrame)(Application.Current.RootVisual);
                }
                return _frame;
            }
            set
            {
                _frame = value;
            }
        }

    }

}
